package fr.cephb.operonj.tools.cmdline.remapper;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Transaction;

import fr.cephb.operonj.core.bio.Observed;
import fr.cephb.operonj.core.db.database.GenomicSeqDB;

/**
 * SNPInfo
 *
 */
public class SNPInfo
	{
	protected static abstract class AbstractSequence
		{
		int buildId=-1;
		int chromId;
		int start;
		int end;
		byte strand;
		int bound_size=-1;
		
		//String seq5="";
		//String observed=null;
		//String seq3="";
		
		
		protected AbstractSequence() {}
		@Override
		public boolean equals(Object obj)
			{
			if(obj==this) return true;
			if(obj==null || !(obj instanceof AbstractSequence)) return false;
			AbstractSequence other=AbstractSequence.class.cast(obj);
			return	chromId==other.chromId &&
					start==other.start &&
					end==other.end &&
					strand==other.strand;
			}
		
		String getSeq5(Transaction txn,GenomicSeqDB seqdb) throws DatabaseException
			{
			return getSeq5(txn,seqdb,bound_size);
			}
		
		String getSeq3(Transaction txn,GenomicSeqDB seqdb) throws DatabaseException
			{
			return getSeq3(txn,seqdb,bound_size);
			}
		
		String getObserved(Transaction txn,GenomicSeqDB seqdb) throws DatabaseException
			{
			return seqdb.getSequence(txn, this.buildId,this.chromId, this.start, this.end);
			}
		
		String getSeq5(Transaction txn,GenomicSeqDB seqdb,int length) throws DatabaseException
			{
			String seq5=seqdb.getSequence(txn, this.buildId, this.chromId, this.start-length, this.start);
			return seq5;
			}
		
		String getSeq3(Transaction txn,GenomicSeqDB seqdb,int length) throws DatabaseException
			{
			String seq3=seqdb.getSequence(txn, this.buildId, this.chromId, this.end, this.end+length);
			return seq3;
			}
		
		
		
		void write(Transaction txn,GenomicSeqDB seqdb,XMLStreamWriter w) throws XMLStreamException,DatabaseException
			{
			w.writeCharacters("\n");
			
			w.writeStartElement("chrom");
			w.writeCharacters(String.valueOf(this.chromId));
			w.writeEndElement();
			
			w.writeCharacters("\n");
			
			w.writeStartElement("strand");
			w.writeCharacters(String.valueOf((char)this.strand));
			w.writeEndElement();
			
			w.writeCharacters("\n");
			
			w.writeStartElement("start");
			w.writeCharacters(String.valueOf(this.start));
			w.writeEndElement();
			
			w.writeCharacters("\n");
			
			w.writeStartElement("end");
			w.writeCharacters(String.valueOf(this.end));
			w.writeEndElement();
			
			w.writeCharacters("\n");
			
			w.writeStartElement("seq5");
			w.writeCharacters(this.getSeq5(txn, seqdb));
			w.writeEndElement();
			w.writeCharacters("\n");
			
			w.writeStartElement("obs");
			w.writeCharacters(this.getObserved(txn, seqdb));
			w.writeEndElement();
			w.writeCharacters("\n");
			
			w.writeStartElement("seq3");
			w.writeCharacters(this.getSeq3(txn,seqdb));
			w.writeEndElement();
			w.writeCharacters("\n");
			
			}
		
		}
	
	public static class SequenceInput
		extends AbstractSequence
		{
		@Override
		void write(Transaction txn,GenomicSeqDB seqdb,XMLStreamWriter w) throws XMLStreamException,DatabaseException
			{
			w.writeStartElement("mapping");
			super.write(txn,seqdb,w);
			w.writeEndElement();
			}
		}
	
	public static class SequenceOutput
	extends AbstractSequence
		{
		String comment="";
		
		@Override
		void write(Transaction txn,GenomicSeqDB seqdb,XMLStreamWriter w) throws XMLStreamException,DatabaseException
			{
			w.writeStartElement("mapping");
			super.write(txn,seqdb,w);
			w.writeStartElement("comment");
			w.writeCharacters(this.comment);
			w.writeEndElement();
			w.writeCharacters("\n");
			
			w.writeEndElement();
			}
		}
	
	/** name for this snp */
	String name="";
	/** rsName for this snp */
	String rsId="";
	
	/** observed variation for this snp */
	Observed observed=null;
	
	/** ncbi seq5 */
	String ncbiSeq5="";
	/** ncbi seq5 */
	Observed ncbiObserved=null;
	/** ncbi seq3 */
	String ncbiSeq3="";
	/** ncbi handles */
	Set<String> ncbiHandles=new HashSet<String>();
	
	/** number of time the left sequence was found */
	int leftHitCount=-1;
	/** number of time the left sequence was found */
	int rightHitCount=-1;
	
	/** declared positions on the first genome */
	List<SequenceInput> positions36=new ArrayList<SequenceInput>();
	/** declared positions on the new genome */
	List<SequenceOutput> positions37=new ArrayList<SequenceOutput>();
	
	
	
	
	
	public String ncbiToFasta(int n)
		{
		int n2 = Math.min(n, ncbiSeq5.length());
		int n3 = Math.min(n, ncbiSeq3.length());
		assert(n2>0);
		assert(n3>0);
		StringBuilder b= new StringBuilder(n2+n3+1);
		for(int i=0;i < n2;++i)
			{
			b.append(ncbiSeq5.charAt(((ncbiSeq5.length()-n2)+i)));
			}
		b.append(this.observed.iupac());
		for(int i=0;i < n3;++i)
			{
			b.append(ncbiSeq3.charAt(i));
			}
		return b.toString();
		}
	
	public boolean isMapped()
		{
		return !this.positions37.isEmpty();
		}
	
	public boolean isMappedOnce()
		{
		return this.positions37.size()==1;
		}
	
	@Override
	public String toString() {
		return ncbiSeq5+"["+ncbiObserved+"]"+ncbiSeq3;
		}
	
	}
